package com.dding.cms.base.web;

import static com.dding.cms.base.web.ActionConstants.ATTACHMENT_UPLOAD_PATH;
import static com.dding.cms.base.web.ActionConstants.PAGE_MODEL_KEY;
import static com.dding.cms.base.web.ActionConstants.VALUE_RESULT_KEY;
import static com.dding.cms.base.web.util.PersistenceUtil.deleteCascadeBoExcept;
import static com.dding.cms.base.web.util.Utils.formatPath;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.dding.core.annotation.Service;
import org.dding.core.log.ILogger;
import org.dding.core.log.LoggerFactory;
import org.dding.core.util.StringUtils;
import org.dding.mvc.ActionSupport;
import org.dding.mvc.InvocationContext;
import org.dding.mvc.annotation.ActionMethod;
import org.dding.mvc.annotation.ActionMethod.ForwardMethod;
import org.dding.mvc.util.Pager;
import org.javalite.activejdbc.Association;
import org.javalite.activejdbc.LazyList;
import org.javalite.activejdbc.Model;
import org.javalite.activejdbc.Paginator;
import org.javalite.activejdbc.associations.Many2ManyAssociation;

import com.dding.cms.base.entity.BaseModel;
import com.dding.cms.base.entity.Content;
import com.dding.cms.base.entity.ContentCount;
import com.dding.cms.base.entity.Site;
import com.dding.cms.base.service.ContentService;
import com.dding.cms.base.service.impl.ContentServiceImpl;
import com.dding.cms.base.web.bo.BaseModelBO;
import com.dding.cms.base.web.bo.ContentListBO;
import com.dding.cms.base.web.bo.UploadFileInvocation;
import com.dding.cms.base.web.util.Configuration;
import com.dding.cms.base.web.util.ContentDeleteCallbackListener;
import com.dding.cms.base.web.util.UploadUtils;
import com.dding.cms.base.web.util.Utils;

@Service(name = "contentAction")
public class ContentAction extends ActionSupport<Object> {

	ContentService contentService = new ContentServiceImpl();

	private ILogger logger = LoggerFactory.getLogger(getClass());
	private String uploadPath;

	public ContentAction() {
		Content.addCallbacks(new ContentDeleteCallbackListener());
	}

	@ActionMethod(
			name = "list", successView = "list.jsp", errorView = "error.html",
			httpMethod = ActionMethod.HttpMethod.ALL,
			invocationClass = Pager.class)
	@SuppressWarnings("unchecked")
	public void list(InvocationContext invocationContext) {
		LazyList<Model> list = Site
				.findBySQL("select site_id,site_name from jc_site");
		Map<Object, Object> sites = new HashMap<Object, Object>();
		for (Model model : list.toArray(new Model[0])) {
			sites.put(model.get("site_id"), model.get("site_name"));
		}
		invocationContext.getPageContext().setAttribute("sites", sites);

		Map<String, String> models = new HashMap<String, String>();
		list = BaseModel
				.findBySQL("select model_id,model_name,has_content,is_disabled from jc_model");
		for (Model model : list.toArray(new Model[0])) {
			Object object = model.get("is_disabled");
			if (object != null) {
				if ((Boolean) object) {
					continue;
				}
				BaseModelBO channelModel = (BaseModelBO) Utils.buildBO(model,
						BaseModelBO.class);
				models.put(channelModel.getModel_id().toString(),
						channelModel.getModel_name());
			}
		}
		invocationContext.getPageContext().setAttribute("models", models);

		String root = invocationContext.getParameterValue("root");

		String query = "select content_id,model_id,title,type_id,author,release_date,status from jc_content";
		if (StringUtils.isNotEmpty(root)) {
			query = "select content_id,model_id,title,type_id,author,release_date,status from jc_content where channel_id in "
					+ "(select channel_id from jc_channel where parent_id = "
					+ root + " or channel_id = " + root + ")";
		}

		Pager pager = (Pager) invocationContext.getInvocation();
		Paginator paginator = new Paginator(Content.class, pager.getPageSize(),
				query).orderBy("release_date desc");

		list = paginator.getPage(pager.getPageNumber());

		List<ContentListBO> contents = new ArrayList<ContentListBO>();
		for (Model model : list.toArray(new Model[0])) {
			ContentListBO listBo = (ContentListBO) Utils.buildBO(model,
					ContentListBO.class);
			LazyList<ContentCount> count = model.get(ContentCount.class,
					"content_id = ?", listBo.getContent_id());
			if (count.size() == 0)
				listBo.setViews(0);
			else
				listBo.setViews((Integer) count.get(0).get("views"));
			contents.add(listBo);
		}

		pager.setTotalCount((int) paginator.getCount());
		pager.setList(contents);
		invocationContext.getPageContext().setAttribute("pager", pager);
		invocationContext.getPageContext().setAttribute("root", root);
	}

	@ActionMethod(
			name = "beforeAdd", successView = "add.jsp",
			errorView = "error.html", httpMethod = ActionMethod.HttpMethod.GET)
	public void beforeAdd(InvocationContext invocationContext) {

		Map<String, Object> result = contentService
				.getPageModel(invocationContext.getParameterMap());
		setInvocationContext(result, invocationContext);
	}

	@ActionMethod(
			name = "upload_attachment",
			httpMethod = ActionMethod.HttpMethod.POST,
			forwardMethod = ForwardMethod.FORWARD,
			invocationClass = UploadFileInvocation.class,
			successView = "../common/attachment_iframe.jsp")
	public void uploadAttachment(InvocationContext invocationContext) {

		if (uploadPath == null)
			uploadPath = (String) Configuration.getBaseConfig().get(
					ATTACHMENT_UPLOAD_PATH);

		UploadFileInvocation invocation = (UploadFileInvocation) invocationContext
				.getInvocation();
		String fileName = invocation.getFiledata().getFilename();

		File file = formatPath(invocationContext.getWebPath(), uploadPath);
		if (file == null) {
			logger.warn("can't upload file,because of folder is not exist.");
			return;
		}
		String ext = FilenameUtils.getExtension(fileName).toLowerCase(
				Locale.ENGLISH);
		String afterName = UploadUtils.generateFilename(ext);
		file = new File(file, afterName);
		if (!file.exists()) {

			try {
				FileUtils.writeByteArrayToFile(file, invocation.getFiledata()
						.getContent());
			} catch (IOException e) {
				logger.error("write upload file " + fileName + " fialue.");
			}
		}

		invocationContext
				.getPageContext()
				.setAttribute(
						"attachmentPath",
						uploadPath.endsWith("/") || uploadPath.endsWith("\\") ? uploadPath
								+ afterName.substring(1)
								: uploadPath + afterName);
		invocationContext.getPageContext().setAttribute("attachmentName",
				fileName);
		invocationContext.getPageContext().setAttribute("attachmentNum",
				invocationContext.getParameterValue("attachmentNum"));
	}

	@ActionMethod(
			name = "add", successView = "list.do", errorView = "error.html",
			httpMethod = ActionMethod.HttpMethod.ALL)
	public void add(InvocationContext invocationContext) {
		contentService.storeContent(invocationContext.getParameterMap());
	}

	@ActionMethod(
			name = "delete", errorView = "error.html",
			forwardMethod = ForwardMethod.FLUSH)
	public void delete(InvocationContext invocationContext) {
		@SuppressWarnings("unchecked")
		List<Association> associations = Content.associations();
		List<Association> params = new ArrayList<Association>();
		for (Association association : associations) {
			if (association instanceof Many2ManyAssociation)
				params.add(association);
		}
		deleteCascadeBoExcept(invocationContext, new Content(), "content_id",
				Association[].class, params.toArray(new Association[0]));
	}

	@ActionMethod(
			name = "update", successView = "list.do", errorView = "error.html",
			httpMethod = ActionMethod.HttpMethod.POST)
	public void update(InvocationContext invocationContext) {
		contentService.updateContent(invocationContext.getParameterMap());
	}

	@ActionMethod(
			name = "edit", successView = "edit.jsp", errorView = "error.html",
			httpMethod = ActionMethod.HttpMethod.GET)
	public void edit(InvocationContext invocationContext) {

		Map<String, Map<String, Object>> result = contentService
				.editContent(invocationContext.getParameterMap());
		invocationContext.getPageContext().setAttribute("attrs",
				result.get(VALUE_RESULT_KEY));
		setInvocationContext(result.get(PAGE_MODEL_KEY), invocationContext);
	}

	private void setInvocationContext(Map<String, Object> result,
			InvocationContext invocationContext) {
		for (Entry<String, Object> entry : result.entrySet()) {
			invocationContext.getPageContext().setAttribute(entry.getKey(),
					entry.getValue());
		}
	}
}